#pragma once

#include <AVUIFrameworkElement.h>
#include <AVUISolidColorBrush.h>

namespace AVUI {

class ControlTemplate;


/// <summary>Represents the base class for user interface (UI) elements that use a <see cref="T:System.Windows.Controls.ControlTemplate" /> to define their appearance. </summary>
class Control : public FrameworkElement
{
public:
    DECLARE_ELEMENT(Control, FrameworkElement);

#pragma region Public Properties

    /// <summary>Gets or sets a brush that describes the background of a control. This is a  dependency property.</summary>
    /// <returns>The brush that is used to fill the background of the control. The default is <see cref="P:System.Windows.Media.Brushes.Transparent" />. </returns>
    TRefCountedPtr<Brush> get_Background() { return (Brush*)GetValue(get_BackgroundProperty()).get_Ptr(); }
    void set_Background(Brush* pValue) { SetValue(get_BackgroundProperty(), (Object*)pValue); } 
    DECLARE_DEPENDENCY_PROPERTY(Background);

    /// <summary>Gets or sets a brush that describes the border background of a control. This is a  dependency property.</summary>
    /// <returns>The brush that is used to fill the control's border; the default is <see cref="P:System.Windows.Media.Brushes.Transparent" />.</returns>
    TRefCountedPtr<Brush> get_BorderBrush() { return (Brush*)GetValue(get_BorderBrushProperty()).get_Ptr(); }
    void set_BorderBrush(Brush* pValue) { SetValue(get_BorderBrushProperty(), (Object*)pValue); } 
    DECLARE_DEPENDENCY_PROPERTY(BorderBrush);

    /// <summary>Gets or sets the border thickness of a control. This is a dependency property. </summary>
    /// <returns>A thickness value; the default is a thickness of 0 on all four sides.</returns>
    Thickness get_BorderThickness() { return AVUI::UnboxValue<Thickness>(GetValue(get_BorderThicknessProperty())); }
    void set_BorderThickness(const Thickness& value) { SetValue(get_BorderThicknessProperty(), AVUI::BoxValue(value)); } 
    DECLARE_DEPENDENCY_PROPERTY(BorderThickness);

    /// <summary>Gets or sets the font family of the control.  This is a dependency property. </summary>
    /// <returns>A font family. The default is the system dialog font.</returns>
    DECLARE_DEPENDENCY_PROPERTY(FontFamily);
    String* get_FontFamily() { return object_cast<String>(GetValue(get_FontFamilyProperty())); }
    void set_FontFamily(String* pFontFamily) { SetValue(get_FontFamilyProperty(), pFontFamily); }

    /// <summary>Gets or sets the font size.  This is a dependency property. </summary>
    /// <returns>The size of the text in the <see cref="T:System.Windows.Controls.Control" />. The default is <see cref="P:System.Windows.SystemFonts.MessageFontSize" />. The font size must be a positive number.</returns>
    float get_FontSize() { return UnboxValue< float >(GetValue(get_FontSizeProperty())); }
    void set_FontSize(float value) { SetValue(get_FontSizeProperty(), AVUI::BoxValue(value)); }
    DECLARE_DEPENDENCY_PROPERTY(FontSize);

    /// <summary>Gets or sets the font style.  This is a dependency property. </summary>
    /// <returns>A <see cref="T:System.Windows.FontStyle" /> value. The default is <see cref="P:System.Windows.FontStyles.Normal" />.</returns>
    String* get_FontStyle() { return object_cast<String>(GetValue(get_FontStyleProperty())); }
    void set_FontStyle(String* pFontStyle) { SetValue(get_FontStyleProperty(), pFontStyle); }
    DECLARE_DEPENDENCY_PROPERTY(FontStyle);

    /// <summary>Gets or sets the weight or thickness of the specified font.  This is a dependency property. </summary>
    /// <returns>A <see cref="T:System.Windows.FontWeight" /> value. The default is <see cref="P:System.Windows.FontWeights.Normal" />.</returns>
    String* get_FontWeight() { return object_cast<String>(GetValue(get_FontWeightProperty())); }
    void set_FontWeight(String* pFontWeight) { SetValue(get_FontWeightProperty(), pFontWeight); }
    DECLARE_DEPENDENCY_PROPERTY(FontWeight);

    /// <summary>Gets or sets a brush that describes the foreground color.   This is a dependency property. </summary>
    /// <returns>The brush that paints the foreground of the control. The default value is the system dialog font color.</returns>
    TRefCountedPtr<Brush> get_Foreground() { return (Brush*)(Object*)GetValue(get_ForegroundProperty()); }
    void set_Foreground(Brush* pValue) { SetValue(get_ForegroundProperty(), (Object*)pValue); } 
    DECLARE_DEPENDENCY_PROPERTY(Foreground);

    /// <summary>Gets or sets the horizontal alignment of the control's content.   This is a dependency property. </summary>
    /// <returns>One of the <see cref="T:System.Windows.HorizontalAlignment" /> values. The default is <see cref="F:System.Windows.HorizontalAlignment.Left" />.</returns>
    HorizontalAlignment::Enum get_HorizontalContentAlignment() { return (HorizontalAlignment::Enum)(AVUI::UnboxValue<int>(GetValue(get_HorizontalContentAlignmentProperty()))); }
    void set_HorizontalContentAlignment(HorizontalAlignment::Enum value) { SetValue(get_HorizontalContentAlignmentProperty(), AVUI::BoxValue<int>(value)); } 
    DECLARE_DEPENDENCY_PROPERTY(HorizontalContentAlignment);

    /// <summary>Gets or sets a value that indicates whether a control is included in tab navigation.  This is a dependency property. </summary>
    /// <returns>true if the control is included in tab navigation; otherwise, false. The default is true.</returns>
    bool get_IsTabStop() { return AVUI::UnboxValue<bool>(GetValue(get_IsTabStopProperty())); }
    void set_IsTabStop(bool value) { SetValue(get_IsTabStopProperty(), AVUI::BoxValue(value)); } 
    DECLARE_DEPENDENCY_PROPERTY(IsTabStop);

    /// <summary>Gets or sets the padding inside a control.  This is a dependency property. </summary>
    /// <returns>The amount of space between the content of a <see cref="T:System.Windows.Controls.Control" /> and its <see cref="P:System.Windows.FrameworkElement.Margin" /> or <see cref="T:System.Windows.Controls.Border" />.  The default is a thickness of 0 on all four sides.</returns>
    Thickness get_Padding() { return AVUI::UnboxValue<Thickness>(GetValue(get_PaddingProperty())); }
    void set_Padding(const Thickness& value) { SetValue(get_PaddingProperty(), AVUI::BoxValue(value)); } 
    DECLARE_DEPENDENCY_PROPERTY(Padding);

    /// <summary>Gets or sets a value that determines the order in which elements receive focus when the user navigates through controls by using the TAB key.  This is a dependency property. </summary>
    /// <returns>A value that determines the order of logical navigation for a device. The default value is <see cref="F:System.Int32.MaxValue" />.</returns>
    int get_TabIndex() { return UnboxValue< int >(GetValue(get_TabIndexProperty())); }
    void set_TabIndex(int value) { SetValue(get_TabIndexProperty(), AVUI::BoxValue(value)); }
    DECLARE_DEPENDENCY_PROPERTY(TabIndex);

    /// <summary>Gets or sets a control template.  This is a dependency property. </summary>
    /// <returns>The template that defines the appearance of the <see cref="T:System.Windows.Controls.Control" />.</returns>
    DECLARE_DEPENDENCY_PROPERTY(Template);
    TRefCountedPtr<ControlTemplate> get_Template() { return m_pTemplateCache; }
    void set_Template(ControlTemplate* pValue) { SetValue(get_TemplateProperty(), (Object*)pValue); } 

    /// <summary>Gets or sets the vertical alignment of the control's content.   This is a dependency property. </summary>
    /// <returns>One of the <see cref="T:System.Windows.VerticalAlignment" /> values. The default is <see cref="F:System.Windows.VerticalAlignment.Top" />.</returns>
    VerticalAlignment::Enum get_VerticalContentAlignment() { return (VerticalAlignment::Enum)(AVUI::UnboxValue<int>(GetValue(get_VerticalContentAlignmentProperty()))); }
    void set_VerticalContentAlignment(VerticalAlignment::Enum value) { SetValue(get_VerticalContentAlignmentProperty(), AVUI::BoxValue<int>(value)); } 
    DECLARE_DEPENDENCY_PROPERTY(VerticalContentAlignment);

#pragma endregion Public Properties

#pragma region Public Events

    /// <summary>Occurs when a mouse button is clicked two or more times. </summary>
    IMPLEMENT_ROUTED_EVENT(MouseDoubleClick, MouseButtonEventArgs, RoutingStrategy::Direct);

    /// <summary>Occurs when a user clicks the mouse button two or more times. </summary>
    IMPLEMENT_ROUTED_EVENT(PreviewMouseDoubleClick, MouseButtonEventArgs, RoutingStrategy::Direct);

#pragma endregion Public Events

protected:

#pragma region Protected Methods

    /// <summary>Called to arrange and size the content of a <see cref="T:System.Windows.Controls.Control" /> object. </summary>
    /// <returns>The size of the control.</returns>
    /// <param name="arrangeBounds">The computed size that is used to arrange the content.</param>
    virtual Size ArrangeOverride(const Size& arrangeBounds) AVUI_OVERRIDE;

    /// <summary>Called to remeasure a control. </summary>
    /// <returns>The size of the control, up to the maximum specified by <paramref name="constraint" />.</returns>
    /// <param name="constraint">The maximum size that the method can return.</param>
    virtual Size MeasureOverride(const Size& constraint) AVUI_OVERRIDE;

    /// <summary>Raises the <see cref="E:System.Windows.Controls.Control.MouseDoubleClick" /> routed event. </summary>
    /// <param name="e">The event data.</param>
    virtual void OnMouseDoubleClick(MouseButtonEventArgs* pE) { RaiseEvent(pE); }

    /// <summary>Raises the <see cref="E:System.Windows.Controls.Control.PreviewMouseDoubleClick" /> routed event. </summary>
    /// <param name="e">The event data. </param>
    virtual void OnPreviewMouseDoubleClick(MouseButtonEventArgs* pE) { RaiseEvent(pE); }

    /// <summary>Called whenever the control's template changes. </summary>
    /// <param name="oldTemplate">The old template.</param>
    /// <param name="newTemplate">The new template.</param>
    virtual void OnTemplateChanged(ControlTemplate* pOldTemplate, ControlTemplate* pNewTemplate) { }

#pragma endregion Protected Methods

#pragma region Protected Properties

    /// <summary>Gets a value that indicates whether a control supports scrolling.</summary>
    /// <returns>true if the control has a <see cref="T:System.Windows.Controls.ScrollViewer" /> in its style and has a custom keyboard scrolling behavior; otherwise, false.</returns>
    virtual bool get_HandlesScrolling() { return false; } 

#pragma endregion Protected Properties

public:

#pragma region Internal Methods

    class ControlBoolFlags
    {
    public:
        enum Enum
        {
            ContentIsNotLogical = 1,
            IsSpaceKeyDown = 2,
            HeaderIsNotLogical = 4,
            CommandDisabled = 8,
            ContentIsItem = 0x10,
            HeaderIsItem = 0x20,
            ScrollHostValid = 0x40,
            ContainsSelection = 0x80
        };
    };

    virtual void OnTemplateChangedInternal(FrameworkTemplate* pOldTemplate, FrameworkTemplate* pNewTemplate) AVUI_OVERRIDE { OnTemplateChanged((ControlTemplate*) pOldTemplate, (ControlTemplate*) pNewTemplate); }
    bool ReadControlFlag(ControlBoolFlags::Enum reqFlag);
    void WriteControlFlag(ControlBoolFlags::Enum reqFlag, bool set);

#pragma endregion Internal Methods

#pragma region Internal Properties

    virtual FrameworkTemplate* get_TemplateCache() AVUI_OVERRIDE { return (FrameworkTemplate*)m_pTemplateCache.get_Ptr(); }
    virtual void set_TemplateCache(FrameworkTemplate* pValue) AVUI_OVERRIDE { m_pTemplateCache = (ControlTemplate*)pValue; }

    virtual FrameworkTemplate* get_TemplateInternal() AVUI_OVERRIDE { return (FrameworkTemplate*)get_Template().get_Ptr(); }

#pragma endregion Internal Properties

#pragma region Internal Fields

    unsigned int m_controlBoolField;

#pragma endregion Internal Fields

private:

#pragma region Private Methods
    static void StaticConstructor();

    static void HandleDoubleClick(Object* pSender, MouseButtonEventArgs* pE);
    static bool IsMarginValid(Object* pValue);
    static void OnTemplateChanged(DependencyObject* pDO, DependencyPropertyChangedEventArgs* pE);

#pragma endregion Private Methods

#pragma region Private Fields

    TRefCountedPtr<ControlTemplate> m_pTemplateCache;

#pragma endregion Private Fields
};


}; // namespace AVUI
